package com.chenfan.mcn.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.chenfan.common.config.Constant;
import com.chenfan.common.exception.BusinessException;
import com.chenfan.mcn.clients.baseinfo.*;
import com.chenfan.mcn.clients.finance.FinanceClient;
import com.chenfan.mcn.clients.privilege.*;
import com.chenfan.mcn.config.UserVoContextHolder;
import com.chenfan.mcn.constant.BillCodeCst;
import com.chenfan.mcn.constant.McnConstant;
import com.chenfan.mcn.constant.NumberCst;
import com.chenfan.mcn.dao.*;
import com.chenfan.mcn.enums.*;
import com.chenfan.mcn.event.EventPublisher;
import com.chenfan.mcn.event.OperateLogEvent;
import com.chenfan.mcn.exception.McnErrorCode;
import com.chenfan.mcn.extension.excel.ExcelUtils;
import com.chenfan.common.extension.validation.groups.Add;
import com.chenfan.common.extension.validation.groups.Modify;
import com.chenfan.mcn.component.CodeGenerateHelper;
import com.chenfan.common.extension.lock.DistributedLockTemplate;
import com.chenfan.mcn.model.*;
import com.chenfan.mcn.model.dto.*;
import com.chenfan.mcn.model.rpc.ChargeClearCallback;
import com.chenfan.mcn.model.vo.*;
import com.chenfan.mcn.mq.producer.StarRebateContractMessageProducer;
import com.chenfan.mcn.service.*;
import com.chenfan.mcn.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 红人返点合同 服务实现类
 * </p>
 *
 * @author wulg
 * @since 2021-11-16
 */
@SuppressWarnings("AlibabaMethodTooLong")
@Slf4j
@Service
public class StarRebateContractServiceImpl implements StarRebateContractService, ApprovalCallbackService {

    @Autowired
    private StarRebateContractMapper starRebateContractMapper;

    @Autowired
    private ContractExcutionOrderService excutionOrderService;

    @Autowired
    private ContractExcutionOrderMapper excutionOrderMapper;

    @Autowired
    private YearFrameContractMapper yearFrameContractMapper;

    @Autowired
    private ExcuteFeedbackMapper excuteFeedbackMapper;

    @Autowired
    private ApprovalFlowService approvalFlowService;

    @Autowired
    private MessageInfoService messageInfoService;

    @Autowired
    private StarRebateContractMessageProducer srcMessageProducer;

    @Autowired
    private FinanceClient financeClient;

    @Autowired
    private BaseInfoClient baseInfoClient;

    @Autowired
    private PrivilegeClient privilegeClient;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private StarBasicDataMapper starBasicDataMapper;

    @Autowired
    private StarBillingHeaderMapper starBillingHeaderMapper;

    @Autowired
    private IncomeContractMapper incomeContractMapper;

    private static final String APPROVAL_KEY = Constant.AUTHORIZATION + ":" + "approval::star_rebate_contract::";

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long insertContract(StarRebateContractSaveDTO saveDTO) {
        List<Long> bindIds = saveDTO.getExcutionOrderIds();
        if(StarRebateStatusEnum.isApproval(saveDTO.getApprovalStatus())) {
            //参数校验后置
            ValidatorUtil.validate(saveDTO, Add.class);
            BusinessAssert.notEmpty(bindIds, McnErrorCode.PARAM_ERROR, "未关联执行单");
        }
        saveDTO.setId(null);
        StarRebateContract starRebateContract = new StarRebateContract();
        BeanUtils.copyProperties(saveDTO, starRebateContract);
        starRebateContract.setApprovalStatus(StarRebateStatusEnum.isApproval(saveDTO.getApprovalStatus()) ?
                StarRebateStatusEnum.APPROVAL.getCode() : StarRebateStatusEnum.UN_COMMIT.getCode());
        starRebateContract.setContractCode(CodeGenerateHelper.getCode(BillCodeCst.STAR_REBATE_APPROVAL));
        boolean result = starRebateContractMapper.insert(starRebateContract) > 0;
        if(result) {
            if(CollectionUtils.isNotEmpty(bindIds)) {
                List<ContractExcutionOrder> existList = excutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                        .in(ContractExcutionOrder::getId, bindIds).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
                BusinessAssert.isTrue(CollectionUtils.isNotEmpty(existList) && existList.size() == bindIds.size(),
                        McnErrorCode.PARAM_ERROR, "存在无效的执行单ID");
                existList.forEach(data -> {
                    this.verifyExcutionOrder(data);
                    ContractExcutionOrder updateExcutionOrder = new ContractExcutionOrder();
                    updateExcutionOrder.setId(data.getId());
                    updateExcutionOrder.setStarRebateId(starRebateContract.getId());
                    updateExcutionOrder.setStarRebateCode(starRebateContract.getContractCode());
                    excutionOrderMapper.updateById(updateExcutionOrder);
                });
            }
            this.startProcessIfNecessary(starRebateContract);
        }
        return starRebateContract.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long updateContract(StarRebateContractSaveDTO saveDTO) {
        StarRebateContract starRebateContract = starRebateContractMapper.selectById(saveDTO.getId());
        BusinessAssert.notNull(starRebateContract, McnErrorCode.DATA_NOT_FOUND);
        saveVertifyStatus(starRebateContract);
        if(StarRebateStatusEnum.isApproval(starRebateContract.getApprovalStatus())) {
            throw new BusinessException(McnErrorCode.DATA_OPERATION_NOT_SUPPORTED.code(), "单据正在审批中，不允许修改！");
        }
        BusinessAssert.isTrue(StarRebateStatusEnum.anyMatch(starRebateContract.getApprovalStatus(),
                StarRebateStatusEnum.UN_COMMIT, StarRebateStatusEnum.CANCEL, StarRebateStatusEnum.REJECTED),
                McnErrorCode.DATA_OPERATION_NOT_SUPPORTED, "当前单据状态-不允许修改！");
        List<Long> bindIds = saveDTO.getExcutionOrderIds();
        StarRebateStatusEnum starRebateStatusEnum = null;
        if(StarRebateStatusEnum.isApproval(saveDTO.getApprovalStatus())) {
            //参数校验后置
            ValidatorUtil.validate(saveDTO, Modify.class);
            BusinessAssert.notEmpty(bindIds, McnErrorCode.PARAM_ERROR, "未关联执行单");
            starRebateStatusEnum = StarRebateStatusEnum.APPROVAL;
        } else {
            starRebateStatusEnum = StarRebateStatusEnum.UN_COMMIT;
        }
        boolean result = starRebateContractMapper.updateByNoStrategy(Wrappers.<StarRebateContract>lambdaUpdate()
                .set(StarRebateContract::getApprovalStatus, starRebateStatusEnum.getCode())
                .set(StarRebateContract::getRebateRatio, saveDTO.getRebateRatio())
                .set(StarRebateContract::getRebateAmount, saveDTO.getRebateAmount())
                .set(StarRebateContract::getStarId, saveDTO.getStarId())
                .set(StarRebateContract::getContractingId, saveDTO.getContractingId())
                .set(StarRebateContract::getStarBillingId, saveDTO.getStarBillingId())
                .set(StarRebateContract::getYearContractId, saveDTO.getYearContractId())
                .set(StarRebateContract::getYearContractCode, saveDTO.getYearContractCode())
                .set(StarRebateContract::getContractFile, saveDTO.getContractFile())
                .set(StarRebateContract::getRemark, saveDTO.getRemark())
                .set(StarRebateContract::getUpdateBy, UserVoContextHolder.getUserId())
                .set(StarRebateContract::getUpdateName, UserVoContextHolder.getUserName())
                .set(StarRebateContract::getUpdateDate, new Date())
                .eq(StarRebateContract::getId, saveDTO.getId()));
        if(result) {
            //查询已绑定的执行单
            List<ContractExcutionOrder> contractExcutionOrderList = excutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                    .eq(ContractExcutionOrder::getStarRebateId, saveDTO.getId()).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
            //解绑执行单
            if(CollectionUtils.isNotEmpty(contractExcutionOrderList)) {
                List<Long> unbindIds = contractExcutionOrderList.stream().map(ContractExcutionOrder::getId).collect(Collectors.toList());
                excutionOrderMapper.updateByNoStrategy(Wrappers.<ContractExcutionOrder>lambdaUpdate()
                        .set(ContractExcutionOrder::getStarRebateId, null).set(ContractExcutionOrder::getStarRebateCode, null)
                        .set(ContractExcutionOrder::getUpdateBy, UserVoContextHolder.getUserId()).set(ContractExcutionOrder::getUpdateName, UserVoContextHolder.getUserName())
                        .set(ContractExcutionOrder::getUpdateDate, new Date()).in(ContractExcutionOrder::getId, unbindIds));
            }
            //绑定执行单
            if(CollectionUtils.isNotEmpty(bindIds)) {
                List<ContractExcutionOrder> existList = excutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                        .in(ContractExcutionOrder::getId, bindIds).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
                BusinessAssert.isTrue(CollectionUtils.isNotEmpty(existList) && existList.size() == bindIds.size(),
                        McnErrorCode.PARAM_ERROR, "存在无效的执行单ID");
                existList.forEach(data -> {
                    this.verifyExcutionOrder(data);
                    ContractExcutionOrder updateExcutionOrder = new ContractExcutionOrder();
                    updateExcutionOrder.setId(data.getId());
                    updateExcutionOrder.setStarRebateId(starRebateContract.getId());
                    updateExcutionOrder.setStarRebateCode(starRebateContract.getContractCode());
                    excutionOrderMapper.updateById(updateExcutionOrder);
                });
            }
            StarRebateContract  newStarRebateContract = starRebateContractMapper.selectById(saveDTO.getId());
            this.startProcessIfNecessary(newStarRebateContract);
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(starRebateContract.getId())
                    .businessType(LogBusinessTypeEnum.STAR_REBATE_CONTRACT)
                    .compare(starRebateContract, newStarRebateContract).build());
        }
        return saveDTO.getId();
    }

    private void saveVertifyStatus(StarRebateContract starRebateContract) {
        if (starRebateContract.getApprovalStatus() != StarRebateStatusEnum.UN_COMMIT.getCode() &&
                starRebateContract.getApprovalStatus() != StarRebateStatusEnum.REJECTED.getCode() &&
                starRebateContract.getApprovalStatus() != StarRebateStatusEnum.CANCEL.getCode()) {
            throw new BusinessException(McnErrorCode.DISCOUNT_APPROVA_UPDATE_ERROR);
        }
    }

    /**
     * 根据条件启动审批流
     * @param starRebateContract
     */
    private void startProcessIfNecessary(StarRebateContract starRebateContract) {
        if(StarRebateStatusEnum.isApproval(starRebateContract.getApprovalStatus())) {
            approvalFlowService.startProcess(starRebateContract.getId(), starRebateContract.getContractCode(), ApprovalEnum.STAR_REBATE_CONTRACT, JSON.toJSONString(starRebateContract));
            stringRedisTemplate.opsForValue().set(APPROVAL_KEY + starRebateContract.getContractCode(), JSONObject.toJSONString(UserVoContextHolder.getUserVo()), 100, TimeUnit.DAYS);
        }
    }

    @Override
    public Page<StarRebateContractListVO> getContractPage(StarRebateContractSearchDTO searchDTO) {
        searchDTO.setAlias("sr.");
        searchDTO.setProcessIds(Arrays.asList(ApprovalEnum.STAR_REBATE_CONTRACT.getProcessId()));
        if (CollectionUtils.isNotEmpty(searchDTO.getFlowStatus())) {
            List<Long> allList = approvalFlowService.getSrcList(searchDTO.getFlowStatus(), searchDTO.getProcessIds());
            if (CollectionUtils.isEmpty(allList)) {
                return new Page<>();
            }
            searchDTO.setSrcIds(allList);
        }
        Page<StarRebateContractListVO> contractPage = starRebateContractMapper.getContractPage(new Page(searchDTO.getPageNum(), searchDTO.getPageSize()), searchDTO);
        List<StarRebateContractListVO> contractList = contractPage.getRecords();
        if (CollectionUtils.isNotEmpty(contractList)) {
            //查询FlowId
            List<Long> idList = contractList.stream().map(StarRebateContractListVO::getId).collect(Collectors.toList());
            Map<Long, Long> flowMap = approvalFlowService.getNewestFlowIds(idList, searchDTO.getProcessIds());
            if (MapUtils.isNotEmpty(flowMap)) {
                contractList.forEach(contract -> {
                    contract.setFlowId(flowMap.get(contract.getId()));
                });
            }
            //查询红人昵称
            List<Long> starIdList = contractList.stream().map(StarRebateContractListVO::getStarId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
            List<StarBasicData> starList = CommonUtil.getIfNecessary(CollectionUtils.isNotEmpty(starIdList), () -> starBasicDataMapper.selectBatchIds(starIdList), null);
            Map<Long, String> starNicknameMap = CommonUtil.defaultList(starList).stream().collect(Collectors.toMap(k -> k.getId(), v -> v.getStarNickname()));
            if(MapUtils.isNotEmpty(starNicknameMap)) {
                contractList.forEach(contract -> {
                    contract.setStarNickname(StringUtils.defaultString(starNicknameMap.get(contract.getStarId())));
                });
            }
            //审批名称
            List<Long> flowIdList = contractList.stream().map(StarRebateContractListVO::getFlowId).filter(Objects::nonNull).collect(Collectors.toList());
            JSONObject flowMapping = approvalFlowService.getFlowStatus(flowIdList);
            if(MapUtils.isNotEmpty(flowMapping)) {
                contractList.forEach(contract -> {
                    contract.setFlowStatusName(CommonUtil.defaultString(flowMapping, contract.getFlowId()));
                });
            }
        }
        return contractPage;
    }

    @Override
    public StarRebateContractDetailVO getContractDetail(Long id) {
        StarRebateContract starRebateContract = starRebateContractMapper.selectById(id);
        BusinessAssert.notNull(starRebateContract, McnErrorCode.DATA_NOT_FOUND);
        StarRebateContractDetailVO starRebateContractDetailVO = new StarRebateContractDetailVO();
        //合同基础信息
        BeanUtils.copyProperties(starRebateContract, starRebateContractDetailVO);
        //审批流信息
        Long flowId = approvalFlowService.getFlowId(id, ApprovalEnum.STAR_REBATE_CONTRACT.getProcessId());
        String stringFlowIds = approvalFlowService.getStringFlowIds(id, ApprovalEnum.STAR_REBATE_CONTRACT.getProcessId());
        starRebateContractDetailVO.setFlowId(flowId);
        starRebateContractDetailVO.setFlowIds(stringFlowIds);
        List<Long> flowList = new ArrayList<>(Collections.singletonList(flowId));
        JSONObject flowMapping = approvalFlowService.getFlowStatus(flowList);
        starRebateContractDetailVO.setFlowStatusName(CommonUtil.defaultString(flowMapping, starRebateContractDetailVO.getFlowId()));
        //查询红人昵称
        if(Objects.nonNull(starRebateContract.getStarId())) {
            StarBasicData starBasicData = starBasicDataMapper.selectById(starRebateContract.getStarId());
            BusinessAssert.notNull(starBasicData, McnErrorCode.STAR_BASIC_DATA_IS_NULL);
            starRebateContractDetailVO.setStarNickname(starBasicData.getStarNickname());
        }
        //查询我司签约主体名称
        List<ScompanyRes> companyResList = privilegeClient.getParList().getObj();
        Map<Long, String> companyMap = companyResList.stream().collect(Collectors.toMap(ScompanyRes::getCompanyId, ScompanyRes::getParentCompanyName));
        starRebateContractDetailVO.setCompanyContractSubject(companyMap.get(starRebateContract.getContractingId()));
        //创建人所属部门
        Map<Long, SDepartment> sDepartmentMap = privilegeClient.getDepartmentByIds(Collections.singletonList(starRebateContract.getDepartmentId())).getObj();
        if(CommonUtil.containsKey(sDepartmentMap, starRebateContract.getDepartmentId())) {
            starRebateContractDetailVO.setDepartmentName(sDepartmentMap.get(starRebateContract.getDepartmentId()).getDepartmentName());
        }
        excutionOrderVoInfo(id, starRebateContract, starRebateContractDetailVO, companyMap);
        //年框合同
        yearFrameContractVoInfo(starRebateContractDetailVO);
        //开票信息
        if (Objects.nonNull(starRebateContractDetailVO.getStarBillingId())) {
            StarBillingHeader starBillingHeader = starBillingHeaderMapper.selectById(starRebateContractDetailVO.getStarBillingId());
            starRebateContractDetailVO.setBillingDetails(starBillingHeader);
        } else {
            starRebateContractDetailVO.setBillingDetails(new StarBillingHeader());
        }
        return starRebateContractDetailVO;
    }

    @Override
    public List<StarRebateContractExportVO> getExportData(StarRebateContractSearchDTO searchDTO) {
        searchDTO.setAlias("sr.");
        searchDTO.setProcessIds(Arrays.asList(ApprovalEnum.STAR_REBATE_CONTRACT.getProcessId()));
        if (CollectionUtils.isNotEmpty(searchDTO.getFlowStatus())) {
            List<Long> allList = approvalFlowService.getSrcList(searchDTO.getFlowStatus(), searchDTO.getProcessIds());
            if(CollectionUtils.isEmpty(allList)) {
                return null;
            }
            searchDTO.setSrcIds(allList);
        }
        List<StarRebateContract> dataList = starRebateContractMapper.getExportData(searchDTO);
        if(CollectionUtils.isEmpty(dataList)) {
            return null;
        }
        //查询FlowId
        List<Long> idList = dataList.stream().map(StarRebateContract::getId).collect(Collectors.toList());
        Map<Long, Long> flowMap = approvalFlowService.getNewestFlowIds(idList, searchDTO.getProcessIds());

        /**
         * 查询红人昵称
         */
        List<Long> starIdList = dataList.stream().map(StarRebateContract::getStarId).filter(Objects::nonNull).collect(Collectors.toList());
        List<StarBasicData> starList = CommonUtil.getIfNecessary(CollectionUtils.isNotEmpty(starIdList), () -> starBasicDataMapper.selectBatchIds(starIdList), null);
        Map<Long, String> starNicknameMap = CommonUtil.defaultList(starList).stream().collect(Collectors.toMap(k -> k.getId(), v -> v.getStarNickname()));
        List<StarRebateContractExportVO> contractList = new ArrayList<>(dataList.size());
        dataList.forEach(data -> {
            StarRebateContractExportVO vo = new StarRebateContractExportVO();
            BeanUtils.copyProperties(data, vo);
            if(MapUtils.isNotEmpty(flowMap)) {
                vo.setFlowId(flowMap.get(vo.getId()));
            }
            vo.setStarNickname(StringUtils.defaultString(starNicknameMap.get(data.getStarId())));
            contractList.add(vo);
        });

        //审批名称
        List<Long> flowList = contractList.stream().map(StarRebateContractExportVO::getFlowId).filter(Objects::nonNull).collect(Collectors.toList());
        JSONObject jsonObject = approvalFlowService.getFlowStatus(flowList);
        contractList.forEach(contract -> {
            contract.setFlowStatusName(CommonUtil.defaultString(jsonObject, contract.getFlowId()));
        });
        return contractList;
    }

    @Override
    public List<StarRebateExcutionOrderExportVO> getExportExcutionOrders(Long id) {
        StarRebateContract starRebateContract = starRebateContractMapper.selectById(id);
        BusinessAssert.notNull(starRebateContract, McnErrorCode.DATA_NOT_FOUND);
        StarRebateExcutionOrderExportVO exportVO = new StarRebateExcutionOrderExportVO();
        //合同基础信息
        BeanUtils.copyProperties(starRebateContract, exportVO);
        //执行单信息
        List<ContractExcutionOrder> executionOrders = null;
        if(StarRebateStatusEnum.isInvalid(starRebateContract.getApprovalStatus())) {
            List<Long> archivedExcuteIds = JSONObject.parseObject(starRebateContract.getArchivedExcuteIds(), new TypeReference<List<Long>>(){});
            if(CollectionUtils.isNotEmpty(archivedExcuteIds)) {
                executionOrders = excutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                        .in(ContractExcutionOrder::getId, archivedExcuteIds).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
            }
        } else {
            executionOrders = excutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                    .eq(ContractExcutionOrder::getStarRebateId, id).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
        }
        if (CollectionUtils.isEmpty(executionOrders)) {
            return new ArrayList<>(0);
        }
        List<Long> excutionOrderIds = executionOrders.stream().map(ContractExcutionOrder::getId).collect(Collectors.toList());
        List<ExcuteFeedback> excuteFeedbackList = excuteFeedbackMapper.selectList(Wrappers.lambdaQuery(ExcuteFeedback.class)
                .in(ExcuteFeedback::getExcutionOrderId, excutionOrderIds)
                .eq(ExcuteFeedback::getIsDelete, NumberCst.ZERO)
        );
        Map<Long, Date> realPublishDateMap = new HashMap<>(excutionOrderIds.size());
        if(CollectionUtils.isNotEmpty(excuteFeedbackList)) {
            excuteFeedbackList.forEach(e -> {
                realPublishDateMap.putIfAbsent(e.getExcutionOrderId(), e.getRealPublishDate());
            });
        }
        //查询红人信息
        List<BasicExcutionOrderVO> excutionOrdersVO = excutionOrderService.basicExcutionOrderList(executionOrders);
        List<StarRebateExcutionOrderExportVO> exportDataList = new ArrayList<>(executionOrders.size());
        excutionOrdersVO.forEach(e -> {
            StarRebateExcutionOrderExportVO exportData = new StarRebateExcutionOrderExportVO();
            exportData.setExcuteCode(e.getExcuteCode());
            exportData.setIncomeContractCode(e.getIncomeContractCode());
            exportData.setBrandName(e.getBrandNameN());
            exportData.setProductName(e.getProductName());
            exportData.setStarNickName(e.getStarNickName());
            exportData.setPublishType(e.getPublishTypeName());
            exportData.setPlatformName(e.getPlatformName());
            exportData.setRealPublishDate(realPublishDateMap.get(e.getId()));
            exportDataList.add(exportData);
        });
        return exportDataList;
    }

    @Override
    public List<StarRebateExcutionOrderVO> importExcel(List<RelatedExcutionOrderInputDTO> inputList) {
        inputList = inputList.stream().filter(t -> StringUtils.isNotBlank(t.getExcuteCode())).collect(Collectors.toList());
        BusinessAssert.notEmpty(inputList, McnErrorCode.IMPORT_CONTENT_EMPTY);
        List<String> excuteCodes = inputList.stream().map(RelatedExcutionOrderInputDTO::getExcuteCode).distinct().collect(Collectors.toList());
        BusinessAssert.isTrue(inputList.size() == excuteCodes.size(), McnErrorCode.PARAM_ERROR, "执行单号存在重复");
        List<ContractExcutionOrder> executionOrders = excutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                .in(ContractExcutionOrder::getExcuteCode, excuteCodes)
                .eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
        BusinessAssert.notEmpty(executionOrders, McnErrorCode.DATA_NOT_FOUND, "执行单编号全部错误");
        Map<String, ContractExcutionOrder> excutionOrderMap = executionOrders.stream().collect(Collectors.toMap(k -> k.getExcuteCode(), v -> v));
        for(String excuteCode : excuteCodes) {
            ContractExcutionOrder entity = excutionOrderMap.get(excuteCode);
            BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND, excuteCode+"-执行单编号错误");
            this.verifyCommonExcutionOrder(entity);
        }
        List<Long> excutionOrderIds = executionOrders.stream().map(ContractExcutionOrder::getId).collect(Collectors.toList());
        List<ExcuteFeedback> excuteFeedbackList = CommonUtil.defaultList(excuteFeedbackMapper.selectList(Wrappers.lambdaQuery(ExcuteFeedback.class)
                .in(ExcuteFeedback::getExcutionOrderId, excutionOrderIds)
                .eq(ExcuteFeedback::getIsDelete, NumberCst.ZERO)));
        Map<Long, Date> realPublishDateMap = new HashMap<>(excutionOrderIds.size());
        if(CollectionUtils.isNotEmpty(excuteFeedbackList)) {
            excuteFeedbackList.forEach(e -> {
                realPublishDateMap.putIfAbsent(e.getExcutionOrderId(), e.getRealPublishDate());
            });
        }
        //查询红人信息
        List<BasicExcutionOrderVO> excutionOrdersVO = excutionOrderService.basicExcutionOrderList(executionOrders);
        List<StarRebateExcutionOrderVO> dataList = new ArrayList<>(executionOrders.size());
        excutionOrdersVO.forEach(e -> {
            StarRebateExcutionOrderVO data = new StarRebateExcutionOrderVO();
            data.setId(e.getId());
            data.setExcuteCode(e.getExcuteCode());
            data.setIncomeContractCode(e.getIncomeContractCode());
            data.setBrandName(e.getBrandName());
            data.setBrandNameN(e.getBrandNameN());
            data.setProductName(e.getProductName());
            data.setStarNickName(e.getStarNickName());
            data.setPublishType(e.getPublishTypeName());
            data.setPlatformName(e.getPlatformName());
            data.setRealPublishDate(realPublishDateMap.get(e.getId()));
            dataList.add(data);
        });
        return dataList;
    }

    @Override
    public void excelDownload(HttpServletResponse response, String fileId) {
        BusinessAssert.isTrue(ImportExcelEnum.match(fileId, ImportExcelEnum.STAR_REBATE_EXCUTION_ORDER), McnErrorCode.EXPORT_FILE_ID_ILLEGAL);
        // 根据FileId判断导出类型
        String excelContent = CommonUtil.defaultIfEmpty(stringRedisTemplate.opsForValue().get(McnConstant.CACHE_PRIFIX + fileId));
        List<RelatedExcutionOrderOutputDTO> outputList =
                JSONObject.parseObject(excelContent, new TypeReference<List<RelatedExcutionOrderOutputDTO>>() {});
        BusinessAssert.notEmpty(outputList, McnErrorCode.EXPORT_HAS_NO_DATA);
        try {
            String title = "红人返点合同-执行单导入失败原因";
            ExcelUtils.exportExcel(outputList, title, RelatedExcutionOrderOutputDTO.class, title + ".xlsx", response);
            stringRedisTemplate.delete(McnConstant.CACHE_PRIFIX + fileId);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    @SuppressWarnings("AlibabaAvoidComplexCondition")
    private void validateStatus(StarRebateContract entity, Integer status) {
        if (entity.getApprovalStatus() == StarRebateStatusEnum.UN_COMMIT.getCode() &&
                (status != StarRebateStatusEnum.APPROVAL.getCode() && status != StarRebateStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_REBATE_CONTRACT_UN_COMMIT_ERROR);
        }
        if (entity.getApprovalStatus() == StarRebateStatusEnum.APPROVAL.getCode() &&
                (status != StarRebateStatusEnum.CANCEL.getCode() && status != StarRebateStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_REBATE_CONTRACT_APPROVAL_ERROR);
        }
        if (entity.getApprovalStatus() == StarRebateStatusEnum.UN_PAYBACK.getCode() &&
                (status != StarRebateStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_REBATE_CONTRACT_UN_PAYBACK_ERROR);
        }
        if (entity.getApprovalStatus() == StarRebateStatusEnum.REJECTED.getCode() &&
                (status != StarRebateStatusEnum.APPROVAL.getCode() && status != StarRebateStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_REBATE_CONTRACT_REJECTED_ERROR);
        }
        if (entity.getApprovalStatus() == StarRebateStatusEnum.CANCEL.getCode() &&
                (status != StarRebateStatusEnum.APPROVAL.getCode() && status != StarRebateStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_REBATE_CONTRACT_CANCEL_ERROR);
        }
        if (entity.getApprovalStatus() == StarRebateStatusEnum.PART_PAYBACK.getCode() &&
                (status != StarRebateStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_REBATE_CONTRACT_PART_PAYBACK_ERROR);
        }
        if (entity.getApprovalStatus() == StarRebateStatusEnum.ALL_PAYBACK.getCode() &&
                (status != StarRebateStatusEnum.INVALID.getCode())) {
            throw new BusinessException(McnErrorCode.STAR_REBATE_CONTRACT_ALL_PAYBACK_ERROR);
        }
    }

    /**
     * 修改-单据状态
     * @param id {@link Long}
     * @param approvalStatus   {@link Integer}
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean changeStatus(Long id, Integer approvalStatus) {
        StarRebateContract entity = starRebateContractMapper.selectById(id);
        BusinessAssert.notNull(entity, McnErrorCode.DATA_NOT_FOUND);
        BusinessAssert.isFalse(StarRebateStatusEnum.isInvalid(entity.getApprovalStatus()), McnErrorCode.BUSINESS_ERROR, "单据已作废！");
        validateStatus(entity, approvalStatus);
        List<Long> archivedExcuteIds = null;
        if (StarRebateStatusEnum.isApproval(approvalStatus)) {
            BusinessAssert.isTrue(StarRebateStatusEnum.anyMatch(entity.getApprovalStatus(),
                    StarRebateStatusEnum.UN_COMMIT, StarRebateStatusEnum.CANCEL, StarRebateStatusEnum.REJECTED),
                    McnErrorCode.BUSINESS_ERROR, "当前单据状态-不允许重新提交审批！");
            //详情页提起审批-校验参数
            StarRebateContractSaveDTO saveDTO = new StarRebateContractSaveDTO();
            BeanUtils.copyProperties(entity, saveDTO);
            ValidatorUtil.validate(saveDTO, Modify.class);
            BusinessAssert.isTrue(excutionOrderMapper.selectCount(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                    .eq(ContractExcutionOrder::getStarRebateId, entity.getId()).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO)) > 0
                    , McnErrorCode.PARAM_ERROR, "未关联执行单-不允许提交审批！");
        } else if (StarRebateStatusEnum.isInvalid(approvalStatus)) {
            if (StarRebateStatusEnum.anyMatch(entity.getApprovalStatus(), StarRebateStatusEnum.UN_PAYBACK, StarRebateStatusEnum.PART_PAYBACK, StarRebateStatusEnum.ALL_PAYBACK)) {
                //判断该单据是否能在财务模块费用表查询到非删除状态的费用
                Integer relatedCount = financeClient.getInvalid(entity.getContractCode(), null, null).getObj();
                BusinessAssert.isTrue(relatedCount <= 0, McnErrorCode.INVALID_FAILED);
            }
            List<ContractExcutionOrder> excutionOrderList = excutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                    .eq(ContractExcutionOrder::getStarRebateId, entity.getId()).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
            if(CollectionUtils.isNotEmpty(excutionOrderList)) {
                archivedExcuteIds = excutionOrderList.stream().map(ContractExcutionOrder::getId).collect(Collectors.toList());
                //释放绑定的执行单
                excutionOrderMapper.updateByNoStrategy(Wrappers.<ContractExcutionOrder>lambdaUpdate()
                        .set(ContractExcutionOrder::getStarRebateId, null)
                        .set(ContractExcutionOrder::getStarRebateCode, null)
                        .set(ContractExcutionOrder::getUpdateBy, UserVoContextHolder.getUserId())
                        .set(ContractExcutionOrder::getUpdateName, UserVoContextHolder.getUserName())
                        .set(ContractExcutionOrder::getUpdateDate, new Date())
                        .in(ContractExcutionOrder::getStarRebateId, entity.getId()));
            }
        }
        StarRebateContract updateEntity = new StarRebateContract();
        updateEntity.setId(entity.getId());
        if(CollectionUtils.isNotEmpty(archivedExcuteIds)) {
            updateEntity.setArchivedExcuteIds(JSONObject.toJSONString(archivedExcuteIds));
        }
        updateEntity.setApprovalStatus(approvalStatus);
        boolean result = starRebateContractMapper.updateById(updateEntity) > 0;
        if (result) {
            //如果红人返点合同撤回或作废，则撤回已提起的审批流程
            if (StarRebateStatusEnum.anyMatch(approvalStatus, StarRebateStatusEnum.CANCEL, StarRebateStatusEnum.INVALID)) {
                approvalFlowService.revokeProcess(entity.getId(), ApprovalEnum.STAR_REBATE_CONTRACT.getProcessId());
            } else if (StarRebateStatusEnum.isApproval(approvalStatus)) {
                approvalFlowService.startProcess(entity.getId(), entity.getContractCode(), ApprovalEnum.STAR_REBATE_CONTRACT, JSON.toJSONString(entity));
                stringRedisTemplate.opsForValue().set(APPROVAL_KEY + entity.getContractCode(), JSONObject.toJSONString(UserVoContextHolder.getUserVo()), 100, TimeUnit.DAYS);
            }
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(entity.getId())
                    .businessType(LogBusinessTypeEnum.STAR_REBATE_CONTRACT)
                    .compare(entity, starRebateContractMapper.selectById(entity.getId()))
                    .build());
        }
        return result;
    }

    @Override
    public StarRebateContract getByCode(String contractCode, Long tenantId) {
        return starRebateContractMapper.selectOne(Wrappers.lambdaQuery(StarRebateContract.class)
                .eq(StarRebateContract::getContractCode, contractCode)
                .eq(StarRebateContract::getTenantId, tenantId)
                .eq(StarRebateContract::getIsDelete, NumberCst.ZERO));
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updatePayback(ChargeClearCallback chargeClearCallback, Long contractId) {
        String clearNo = chargeClearCallback.getClearNo();
        BigDecimal paybackAmount = chargeClearCallback.getPaybackAmount();
        MessageTopicEnum topicEnum = MessageTopicEnum.PAYBACK_CALLBACK_HRFD;
        StarRebateContract starRebateContract = starRebateContractMapper.selectById(contractId);
        BusinessAssert.notNull(starRebateContract, McnErrorCode.DATA_NOT_FOUND, String.format("【%s】查询不到该合同", topicEnum.getDesc()));
        //是否冲销
        boolean isChargeAgainst = paybackAmount.compareTo(BigDecimal.ZERO) == -1;
        Date now = new Date();
        //更新红人返点合同回款金额
        StarRebateContract updateContract = new StarRebateContract();
        updateContract.setPaybackAmount(paybackAmount.add(ObjectUtils.defaultIfNull(starRebateContract.getPaybackAmount(), BigDecimal.ZERO)));
        BusinessAssert.isTrue(updateContract.getPaybackAmount().compareTo(BigDecimal.ZERO) != -1,
                McnErrorCode.PARAM_ERROR, String.format("【%s】计算后已回款金额为负数", topicEnum.getDesc()));
        updateContract.setPaybackDate(ObjectUtils.defaultIfNull(chargeClearCallback.getPaybackDate(), now));
        if(BigDecimal.ZERO.compareTo(updateContract.getPaybackAmount()) == 0) {
            updateContract.setApprovalStatus(StarRebateStatusEnum.UN_PAYBACK.getCode());
        } else if (starRebateContract.getRebateAmount().compareTo(updateContract.getPaybackAmount()) == 1) {
            updateContract.setApprovalStatus(StarRebateStatusEnum.PART_PAYBACK.getCode());
        } else {
            updateContract.setApprovalStatus(StarRebateStatusEnum.ALL_PAYBACK.getCode());
        }
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("billNo", clearNo);
        jsonObject.put("amount", paybackAmount);
        jsonObject.put("contractCode", starRebateContract.getContractCode());
        jsonObject.put("totalAmount", updateContract.getPaybackAmount());
        String messageBody = jsonObject.toJSONString();
        String messageKey = StringUtils.joinWith(isChargeAgainst ? "-" : "+", clearNo, starRebateContract.getContractCode());
        String signature = CommonUtil.hmacMd5Hex(messageBody);
        MessageInfo messageInfo = MessageInfo.builder().messageTopic(topicEnum.name()).messageKey(messageKey)
                .tenantId(starRebateContract.getTenantId())
                .messageBody(messageBody).signature(signature).status(MessageStatusEnum.SUCCESS.getType()).build();
        if (!messageInfoService.addMessageInfo(messageInfo)) {
            MessageInfo entity = messageInfoService.selectOne(Wrappers.lambdaQuery(MessageInfo.class)
                    .eq(MessageInfo::getMessageTopic, topicEnum.name())
                    .eq(MessageInfo::getMessageKey, messageKey)
                    .eq(MessageInfo::getTenantId, starRebateContract.getTenantId())
                    .eq(MessageInfo::getIsDelete, Boolean.FALSE)
            );
            BusinessAssert.notNull(entity, McnErrorCode.BUSINESS_ERROR, String.format("【%s】数据幂等处理异常", topicEnum.getDesc()));
            //判断消息内容签名，如果相等，重复回调
            if (signature.equals(entity.getSignature())) {
                //也可以进一步比较金额
                return true;
            }
            JSONObject payload = JSONObject.parseObject(entity.getMessageBody());
            String preBillNo = payload.getString("billNo");
            BigDecimal preAmount = payload.getBigDecimal("amount");
            String preContractCode = payload.getString("contractCode");
            throw new BusinessException(McnErrorCode.BUSINESS_ERROR.code(),
                    String.format("【%s】重复请求！上次回调：单据号=%s，金额=%s，合同号=%s", topicEnum.getDesc(), preBillNo, preAmount, preContractCode));
        }
        updateContract.setId(starRebateContract.getId());
        updateContract.setUpdateBy(chargeClearCallback.getOperatorId());
        updateContract.setUpdateName(chargeClearCallback.getOperatorName());
        updateContract.setUpdateDate(now);
        boolean result = starRebateContractMapper.updateById(updateContract) > 0;
        if(result) {
            //红人返点合同已回款后，关联待打款的执行单-置为已打款
            if(StarRebateStatusEnum.isAllPayback(updateContract.getApprovalStatus())) {
                excutionOrderMapper.updateByNoStrategy(Wrappers.<ContractExcutionOrder>lambdaUpdate()
                        .set(ContractExcutionOrder::getApprovalStatus, ExcutionApprovalStatusEnum.PAID.getCode())
                        .set(ContractExcutionOrder::getUpdateBy, chargeClearCallback.getOperatorId())
                        .set(ContractExcutionOrder::getUpdateName, chargeClearCallback.getOperatorName())
                        .set(ContractExcutionOrder::getUpdateDate, now)
                        .eq(ContractExcutionOrder::getStarRebateId, starRebateContract.getId())
                        .eq(ContractExcutionOrder::getApprovalStatus, ExcutionApprovalStatusEnum.PASSED.getCode())
                );
                //查询已回款-未入住红人执行单
                List<ContractExcutionOrder> excutionOrderList = excutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                        .eq(ContractExcutionOrder::getStarRebateId, starRebateContract.getId())
                        .eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
                Map<Long, BigDecimal> incomePaybackMap = CommonUtil.defaultList(excutionOrderList).stream().collect(Collectors.groupingBy(ContractExcutionOrder::getIncomeContractId,
                        HashMap::new, Collectors.reducing(BigDecimal.ZERO, ContractExcutionOrder::getActualQuotedPrice, BigDecimal::add)));
                if(MapUtils.isNotEmpty(incomePaybackMap)) {
                    incomePaybackMap.entrySet().forEach(e -> {
                        DistributedLockTemplate.execute(OperateLockEnum.INCOME_CONTRACT.generateKey(e.getKey()), () -> {
                            IncomeContract incomeContract = incomeContractMapper.selectById(e.getKey());
                            if(Objects.nonNull(incomeContract)) {
                                //更新收入合同回款金额
                                IncomeContract updateIncomeContract = new IncomeContract();
                                updateIncomeContract.setId(incomeContract.getId());
                                updateIncomeContract.setPayBackAmount(e.getValue().add(ObjectUtils.defaultIfNull(incomeContract.getPayBackAmount(), BigDecimal.ZERO)));
                                if(BigDecimal.ZERO.compareTo(updateIncomeContract.getPayBackAmount()) == 0) {
                                    updateIncomeContract.setPayBackStatus(NumberCst.ZERO);
                                } else if (incomeContract.getBusinessAmount().compareTo(updateIncomeContract.getPayBackAmount()) == 1) {
                                    updateIncomeContract.setPayBackStatus(NumberCst.ONE);
                                } else if (incomeContract.getBusinessAmount().compareTo(updateIncomeContract.getPayBackAmount()) == 0) {
                                    updateIncomeContract.setPayBackStatus(NumberCst.TWO);
                                } else {
                                    //理论上不存在 回款金额大于合同金额
                                    updateIncomeContract.setPayBackStatus(NumberCst.TWO);
                                }
                                incomeContractMapper.updateById(updateIncomeContract);
                                //操作日志
                                EventPublisher.post(OperateLogEvent.builder().businessId(incomeContract.getId())
                                        .businessType(LogBusinessTypeEnum.INCOME_CONTRACT)
                                        .compare(incomeContract, incomeContractMapper.selectById(incomeContract.getId()))
                                        .build(starRebateContract.getCreateBy(), starRebateContract.getCreateName()));
                            }
                            return true;
                        });
                    });
                }
            }
            //操作日志
            EventPublisher.post(OperateLogEvent.builder().businessId(starRebateContract.getId())
                    .businessType(LogBusinessTypeEnum.STAR_REBATE_CONTRACT)
                    .compare(starRebateContract, starRebateContractMapper.selectById(starRebateContract.getId()))
                    .build(starRebateContract.getCreateBy(), starRebateContract.getCreateName()));
        }
        return result;
    }

    /**
     * 审批流回调
     * @param approvalFlowDTO 流程对对象
     * @param status 最后节点的同意 false 拒绝
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void approvalCallback(ApprovalFlowDTO approvalFlowDTO, Boolean status) {
        StarRebateContract starRebateContract = starRebateContractMapper.selectById(approvalFlowDTO.getSrcId());
        BusinessAssert.notNull(starRebateContract, McnErrorCode.DATA_NOT_FOUND);
        approvalFlowDTO.setSrcCode(starRebateContract.getContractCode());
        approvalFlowDTO.addSubmitInfoIfNull(starRebateContract);
        if (Objects.isNull(status)) {
            //审批流配置-接入待办
            return;
        }
        //流程审批结束
        Integer approvalStatus = status.booleanValue() ? StarRebateStatusEnum.UN_PAYBACK.getCode() : StarRebateStatusEnum.REJECTED.getCode();
        if (StarRebateStatusEnum.anyMatch(starRebateContract.getApprovalStatus(), StarRebateStatusEnum.UN_PAYBACK, StarRebateStatusEnum.REJECTED)) {
            log.error("红人返点合同-流程审批结束重复回调，不做处理！approvalId={}", approvalFlowDTO.getApprovalId());
            return;
        }
        BusinessAssert.isTrue(DistributedLockTemplate.execute(OperateLockEnum.STAR_REBATE_CONTRACT.generateKey(starRebateContract.getId()), () -> {
            StarRebateContract updateEntity = new StarRebateContract();
            updateEntity.setId(starRebateContract.getId());
            updateEntity.setApprovalStatus(approvalStatus);
            updateEntity.setUpdateBy(approvalFlowDTO.getUserId());
            updateEntity.setUpdateName(approvalFlowDTO.getUserName());
            updateEntity.setUpdateDate(new Date());
            boolean result = starRebateContractMapper.updateById(updateEntity) > 0;
            if(result) {
                //操作日志
                EventPublisher.post(OperateLogEvent.builder().businessId(starRebateContract.getId())
                        .businessType(LogBusinessTypeEnum.STAR_REBATE_CONTRACT)
                        .compare(starRebateContract, starRebateContractMapper.selectById(starRebateContract.getId()))
                        .build());
            }
            return result;
        }), McnErrorCode.FLOW_CALLBACK_HANDLE_EXCEPTION);

        // 待回款(审批通过) => 生成费用推送财务系统
        if (StarRebateStatusEnum.unPackback(approvalStatus)) {
            srcMessageProducer.sendRecordToMq(starRebateContract.getId());
        }
        //发送流程结束通知
        approvalFlowService.sendNotify(approvalFlowDTO, starRebateContract.getId(), starRebateContract.getContractCode(),
                ApprovalEnum.STAR_REBATE_CONTRACT, status, starRebateContract.getCreateBy(), starRebateContract.getCreateName());
    }

    /**
     * 组装执行单信息
     * @param id
     * @param starRebateContract
     * @param starRebateContractDetailVO
     */
    private void excutionOrderVoInfo(Long id, StarRebateContract starRebateContract, StarRebateContractDetailVO starRebateContractDetailVO, Map<Long, String> companyMap) {
        //执行单信息
        List<ContractExcutionOrder> executionOrders = null;
        if(StarRebateStatusEnum.isInvalid(starRebateContract.getApprovalStatus())) {
            List<Long> archivedExcuteIds = JSONObject.parseObject(starRebateContract.getArchivedExcuteIds(), new TypeReference<List<Long>>(){});
            if(CollectionUtils.isNotEmpty(archivedExcuteIds)) {
                executionOrders = excutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                        .in(ContractExcutionOrder::getId, archivedExcuteIds).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
            }
        } else {
            executionOrders = excutionOrderMapper.selectList(Wrappers.lambdaQuery(ContractExcutionOrder.class)
                    .eq(ContractExcutionOrder::getStarRebateId, id).eq(ContractExcutionOrder::getIsDelete, NumberCst.ZERO));
        }
        if (CollectionUtils.isNotEmpty(executionOrders)) {
            List<Long> incomeContractIds = executionOrders.stream().map(ContractExcutionOrder::getIncomeContractId).distinct().collect(Collectors.toList());
            Map<Long, String> companyContractSubjectMap = CommonUtil.defaultList(incomeContractMapper.selectBatchIds(incomeContractIds))
                    .stream().filter(e -> StringUtils.isNotBlank(e.getCompanyContractSubject())).collect(Collectors.toMap(k -> k.getId(), v -> v.getCompanyContractSubject()));

            List<Long> excutionOrderIds = executionOrders.stream().map(ContractExcutionOrder::getId).collect(Collectors.toList());
            List<ExcuteFeedback> excuteFeedbackList = CommonUtil.defaultList(excuteFeedbackMapper.selectList(Wrappers.lambdaQuery(ExcuteFeedback.class)
                    .in(ExcuteFeedback::getExcutionOrderId, excutionOrderIds).eq(ExcuteFeedback::getIsDelete, NumberCst.ZERO)));
            Map<Long, Date> realPublishDateMap = new HashMap<>(excutionOrderIds.size());
            if(CollectionUtils.isNotEmpty(excuteFeedbackList)) {
                excuteFeedbackList.forEach(e -> realPublishDateMap.putIfAbsent(e.getExcutionOrderId(), e.getRealPublishDate()));
            }

            //查询红人信息
            List<BasicExcutionOrderVO> excutionOrdersVO = excutionOrderService.basicExcutionOrderList(executionOrders);
            List<StarRebateExcutionOrderVO> dataList = new ArrayList<>(executionOrders.size());
            excutionOrdersVO.forEach(e -> {
                StarRebateExcutionOrderVO data = new StarRebateExcutionOrderVO();
                data.setId(e.getId());
                data.setExcuteCode(e.getExcuteCode());
                data.setIncomeContractId(e.getIncomeContractId());
                data.setIncomeContractCode(e.getIncomeContractCode());
                data.setBrandName(e.getBrandNameN());
                data.setProductName(e.getProductName());
                data.setStarNickName(e.getStarNickName());
                data.setPublishType(e.getPublishTypeName());
                data.setPlatformName(e.getPlatformName());
                data.setRealPublishDate(realPublishDateMap.get(e.getId()));
                data.setCompanyContractSubjectName(companyContractSubjectMap.get(e.getIncomeContractId()));
                data.setActualQuotedPrice(e.getActualQuotedPrice());
                data.setPlatNickName(e.getPlatNickName());
                data.setPublishForm(e.getPublishFormName());
                dataList.add(data);
            });
            starRebateContractDetailVO.setExcutionOrders(dataList);
        }
    }

    /**
     * 构建年框合同信息
     * @param starRebateContractDetailVO
     */
    private void yearFrameContractVoInfo(StarRebateContractDetailVO starRebateContractDetailVO) {
        if (Objects.nonNull(starRebateContractDetailVO.getYearContractId())) {
            YearFrameContract yearFrameContract = yearFrameContractMapper.selectById(starRebateContractDetailVO.getYearContractId());
            YearFrameContractVO yearFrameContractVO = new YearFrameContractVO();
            BeanUtils.copyProperties(yearFrameContract, yearFrameContractVO);
            List<String> dictProfileList = new ArrayList<>(Collections.singletonList("yearFrameContract"));
            List<String> dictList = Collections.singletonList(yearFrameContractVO.getContractType());
            Map<String, String> dictMapping = Objects.requireNonNull(baseInfoClient.getDescByCode(new DescByCodeDTO()
                    .setDictsCodes(dictList).setProfileCodes(dictProfileList))).getObj();
            if (Objects.nonNull(dictMapping)) {
                yearFrameContractVO.setContractTypeName(dictMapping.get(dictProfileList.get(0) + ";" + yearFrameContractVO.getContractType()));
            }
            starRebateContractDetailVO.setYearFrameContractVO(yearFrameContractVO);
        } else {
            starRebateContractDetailVO.setYearFrameContractVO(new YearFrameContractVO());
        }
    }


    /**
     * 红人返点合同-校验执行单
     * @param entity
     */
    private void verifyExcutionOrder(ContractExcutionOrder entity) {
        verifyCommonExcutionOrder(entity);
        BusinessAssert.isTrue(Objects.isNull(entity.getStarRebateId()), McnErrorCode.DATA_EXISTED, String.format("【执行单-%s】已存在【红人返点合同-%s】关联", entity.getExcuteCode(), entity.getStarRebateCode()));
    }

    /**
     * 红人返点合同-校验公共执行单
     * @param entity
     */
    private void verifyCommonExcutionOrder(ContractExcutionOrder entity) {
        BusinessAssert.isTrue(ExcutionOrderTypeEnum.isOutside(entity.getType()), McnErrorCode.PARAM_ERROR, String.format("【执行单-%s】执行单类型-须为【外部红人执行单】", entity.getExcuteCode()));
        BusinessAssert.isFalse(ExcutionApprovalStatusEnum.anyMatch(entity.getApprovalStatus(), ExcutionApprovalStatusEnum.PAID, ExcutionApprovalStatusEnum.INVALID),
                McnErrorCode.PARAM_ERROR, String.format("执行单【%s】单据状态-须非【已打款或已作废】", entity.getExcuteCode()));
//        BusinessAssert.isTrue(NumberCst.ZERO.equals(entity.getInSystemAdmin()), McnErrorCode.PARAM_ERROR, String.format("【执行单-%s】是否打款至红人-须为【否】", entity.getExcuteCode()));
    }
}
